// 交叉类型
type O1 = { name: string }
type O2 = { age: number }
type O3 = Obj1 & Obj2
let o: O3 = { name: "张三", age: 18 }

// 通用交叉方法
type ObjectType<T> = T extends object ? T : never
function cross<T, U>(obj1: ObjectType<T>, obj2: ObjectType<U>): T & U;
function cross<T, U, K>(obj1: ObjectType<T>, obj2: ObjectType<U>, obj3: ObjectType<K>): T & U & K;
// 为什么实现签名的obj3需要设置为可选，因为第一个重载签名声明了，可以只接受2个参数，所以后面的参数都是可选了。
function cross<T, U, K>(obj1: ObjectType<T>, obj2: ObjectType<U>, obj3?: ObjectType<K>): T & U & K {
  let combine = {} as T & U & K
  union(combine, obj1)
  union(combine, obj2)
  union(combine, obj3)  // 当obj3为undefined时，for循环是不会执行的。就符合T & U类型了。
  return combine
}
function union (combine: any, obj: any) {
  for (let key in obj) { (combine as any)[key] = obj[key] }  // combine中不包含obj1的属性，所以要断言为any
}

type Obj1 = { name: string }
type Obj2 = { age: number }
type Obj3 = { address: string }
let obj1: Obj1 = { name: "张三" }
let obj2: Obj2 = { age: 18 }
let obj3: Obj3 = { address: "广州" }

console.log(cross(obj1, obj2))
console.log(cross(obj1, obj2, obj3))

export {}